package at.horario.web.pages;

import at.horario.model.User;
import at.horario.service.RoleManager;
import at.horario.service.UserManager;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.form.AjaxFormValidatingBehavior;
import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.extensions.markup.html.form.palette.Palette;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.*;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.util.collections.MicroMap;
import org.apache.wicket.util.string.interpolator.MapVariableInterpolator;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.validator.AbstractValidator;

@AuthorizeInstantiation({"user", "admin"})

public class UserForm extends PageTemplate {
    @SpringBean
    private UserManager userManager;
    @SpringBean
    private RoleManager roleManager;
    private final Page backPage;

    /**
     * Constructor user to create a new user
     *
     * @param backPage page to navigate to after this page completes its work
     */
    public UserForm(Page backPage) {
        this(backPage, new User());
    }

    public UserForm() {
        this(new Index());
    }


    /**
     * Constructor used to edit an user
     *
     * @param backPage page to navigate to after this page completes its work
     * @param user     user to edit
     */
    public UserForm(final Page backPage, User user) {
        this.backPage = backPage;

        // Create and add the form
        EditForm form = new EditForm("user-form", user) {
            protected void onSave(User user) {
                onSaveUser(user);
            }

            protected void onCancel() {
                onCancelEditing();
            }

            protected void onDelete(User user) {
                onDeleteUser(user);
            }
        };
        add(form);
    }

    /**
     * Listener method for save action
     *
     * @param user user bean
     */
    protected void onSaveUser(User user) {
        userManager.saveOrUpdate(user);

        String message = MapVariableInterpolator.interpolate(getLocalizer().getString("user.saved", this),
                new MicroMap("name", user.getFullName()));
        getSession().info(message);

        setRedirect(true);
        setResponsePage(backPage);
    }

    /**
     * Listener method for delete action
     *
     * @param user user bean
     */
    protected void onDeleteUser(User user) {
        userManager.remove(user.getId());

        String message = MapVariableInterpolator.interpolate(getLocalizer().getString("user.deleted", this),
                new MicroMap("name", user.getFullName()));
        getSession().info(message);

        setRedirect(true);
        setResponsePage(backPage);
    }

    /**
     * Lister method for cancel action
     */
    private void onCancelEditing() {
        setResponsePage(backPage);
    }

    /**
     * Subclass of Form used to edit an user
     *
     * @author ivaynberg
     */
    private abstract class EditForm extends BaseForm {

        /**
         * Constructor
         *
         * @param id   component id
         * @param user User object that will be used as a form bean
         */
        public EditForm(String id, User user) {
            /*
             * We wrap the user bean with a CompoundPropertyModel, this allows
             * us to easily connect form components to the bean properties
             * (component id is used as the property expression)
             */
            super(id, new CompoundPropertyModel(user));
            final RequiredTextField username = new RequiredTextField("username");

            if (user.getId() == null)
                username.add(new AbstractValidator() {
                    @Override
                    protected String resourceKey() {
                        return "username.existe";
                    }

                    @Override
                    protected void onValidate(IValidatable validatable) {
                        if (userManager.exists((String) validatable.getValue())) {
                            error(validatable);
                        }
                    }
                });

            final PasswordTextField password = new PasswordTextField("password");
            password.setResetPassword(false);
            password.setRequired(true);

            final PasswordTextField confirmPassword = new PasswordTextField("confirmPassword");
            confirmPassword.setResetPassword(false);
            confirmPassword.setRequired(true);

            confirmPassword.add(new AbstractValidator() {
                @Override
                protected String resourceKey() {
                    return "password.diferent";
                }

                @Override
                protected void onValidate(IValidatable validatable) {
                    if (!validatable.getValue().equals(password.getValue())) {
                        error(validatable);
                    }
                }
            });


            final RequiredTextField passwordHint = new RequiredTextField("passwordHint");

            final TextField firstName = new TextField("firstName");
            final RequiredTextField lastName = new RequiredTextField("lastName");

            final CheckBox enabled = new CheckBox("enabled");
            final CheckBox accountExpired = new CheckBox("accountExpired");
            final CheckBox accountLocked = new CheckBox("accountLocked");
            final CheckBox credentialsExpired = new CheckBox("credentialsExpired");

            //Palette palette = new Palette("roles", );

            Palette role = new Palette("roles", new Model(roleManager.getRoles()), new ChoiceRenderer("name", "id"), 6, false);


            addField(username);
            addField(password);
            addField(confirmPassword);
            addField(passwordHint);
            addField(firstName);
            addField(lastName);

            addField(enabled);
            addField(accountExpired);
            addField(accountLocked);
            addField(credentialsExpired);


            add(role);

            AjaxFormValidatingBehavior.addToAllFormComponents(this, "onblur", org.apache.wicket.util.time.Duration.ONE_SECOND);


            add(new Button("save", new Model("Save")) {
                public void onSubmit() {
                    onSave((User) getForm().getModelObject());
                }
            });

            Button delete = new Button("delete", new Model("Delete")) {
                public void onSubmit() {
                    onDelete((User) getForm().getModelObject());
                }
            };

            if (user.getId() == null) {
                delete.setVisible(false);
                delete.setEnabled(false);
            }
            add(delete);

            /*
             * Notice the setDefaultFormProcessing(false) call at the end. This
             * tells wicket that when this button is pressed it should not
             * perform any form processing (ie bind request values to the bean).
             */
            add(new Button("cancel", new Model("Cancel")) {
                public void onSubmit() {
                    onCancel();
                }
            }.setDefaultFormProcessing(false));

        }


        private void addField(final FormComponent fc) {
            final String key = "user." + fc.getId();
            final ResourceModel model = new ResourceModel(key);
            add(fc, model);
            final Label label = new Label(fc.getId() + "label", getLocalizer().getString(key, UserForm.this) + "<span class=\"req\">*</span>");
            label.setEscapeModelStrings(false);
            add(label);
            fc.setOutputMarkupId(true);
            label.add(new AttributeModifier("for", true, new AbstractReadOnlyModel() {
                public Object getObject() {
                    return fc.getMarkupId();
                }
            }));
        }

        /**
         * Callback for cancel button
         */
        protected abstract void onCancel();

        /**
         * Callback for delete button
         *
         * @param user user bean
         */
        protected abstract void onDelete(User user);

        /**
         * Callback for save button
         *
         * @param user user bean
         */
        protected abstract void onSave(User user);
    }
}
